﻿using System;
using System.Collections;
using System.Collections.Generic;
using Assist;
using Autodesk.Revit.DB;
using Autodesk.Revit.DB.Mechanical;
using YArchitech.Revit;

namespace YArchitech.HCLoad.Utils
{
	internal class HcGeomUtil
	{
		public static bool FaceCutSurface(Face face, Element surface)
		{
			foreach (GeometryObject geometryObject in RevitVersionFuncs.GetGeometryObjectArray(surface.get_Geometry(new Options())))
			{
				Solid solid = geometryObject as Solid;
				if (!(solid == null) && solid.Faces.Size != 0)
				{
					foreach (object obj in solid.Faces)
					{
						Face roomFace = (Face)obj;
						if (HcGeomUtil.IsSubset(face, roomFace))
						{
							return true;
						}
					}
				}
			}
			return false;
		}

		public static Solid SurfaceCutElement(Element surface, Element element)
		{
			GeometryObject geometryObject = null;
			Space space = element as Space;
			if (space != null)
			{
				geometryObject = RevitVersionFuncs.GetGeometryObjectArray(space.ClosedShell)[0];
			}
			if (null != geometryObject)
			{
				return HcGeomUtil.SurfaceCutSpaceGeometry(surface, geometryObject);
			}
			return null;
		}

		public static Solid SurfaceCutSpaceGeometry(Element surface, GeometryObject spaceGeomArray)
		{
			Solid roomSolid = spaceGeomArray as Solid;
			foreach (GeometryObject geometryObject in RevitVersionFuncs.GetGeometryObjectArray(surface.get_Geometry(new Options())))
			{
				Solid solid = geometryObject as Solid;
				if (!(solid == null) && solid.Faces.Size != 0 && HcGeomUtil.SolidsCut(solid, roomSolid))
				{
					return solid;
				}
			}
			return null;
		}

		public static bool SolidsCut(Solid roofSolid, Solid roomSolid)
		{
			if (roofSolid.Faces.Size == 0 || roomSolid.Faces.Size == 0)
			{
				return false;
			}
			foreach (object obj in roomSolid.Faces)
			{
				Face roomFace = (Face)obj;
				IEnumerator enumerator2 = roofSolid.Faces.GetEnumerator();
				{
					while (enumerator2.MoveNext())
					{
						if (HcGeomUtil.IsSubset((Face)enumerator2.Current, roomFace))
						{
							return true;
						}
					}
				}
			}
			return false;
		}

		public static bool IsSubset(Face roofFace, Face roomFace)
		{
			return !(null == roofFace) && !(null == roomFace) && !(roofFace.GetType() != roomFace.GetType()) && HcGeomUtil.FacesCoincident(roofFace, roomFace) && HcGeomUtil.FacesOverlap(roofFace, roomFace);
		}

		public static bool FacesOverlap(Face roofFace, Face roomFace)
		{
			if (null == roofFace || null == roomFace)
			{
				return false;
			}
			foreach (object obj in roomFace.EdgeLoops)
			{
				foreach (object obj2 in ((EdgeArray)obj))
				{
					foreach (XYZ xyz in (((Edge)obj2).Tessellate() as List<XYZ>))
					{
						IntersectionResult intersectionResult = roofFace.Project(xyz);
						if (intersectionResult != null && Math.Abs(intersectionResult.Distance) > 1.0)
						{
							return false;
						}
					}
				}
			}
			return true;
		}

		public static bool FacesCoincident(Face roofFace, Face roomFace)
		{
			if (roofFace is PlanarFace)
			{
				return HcGeomUtil.PlanarFacesCoincident(roofFace as PlanarFace, roomFace as PlanarFace);
			}
			if (roofFace is ConicalFace)
			{
				return HcGeomUtil.ConicalFacesCoincident(roofFace as ConicalFace, roomFace as ConicalFace);
			}
			if (roofFace is CylindricalFace)
			{
				return HcGeomUtil.CylindricalFacesCoincident(roofFace as CylindricalFace, roomFace as CylindricalFace);
			}
			if (roofFace is RevolvedFace)
			{
				return HcGeomUtil.RevolvedFacesCoincident(roofFace as RevolvedFace, roomFace as RevolvedFace);
			}
			if (roofFace is HermiteFace)
			{
				return HcGeomUtil.HermiteFacesCoincident(roofFace as HermiteFace, roomFace as HermiteFace);
			}
			if (roofFace is RuledFace)
			{
				return HcGeomUtil.RuledFacesCoincident(roofFace as RuledFace, roomFace as RuledFace);
			}
			throw new Exception("Not supported face type: " + roofFace.GetType().Name);
		}

		public static bool RuledFacesCoincident(RuledFace f1, RuledFace f2)
		{
			if (null == f1 || null == f2)
			{
				return false;
			}
			Curve c = f1.get_Curve(0);
			Curve c2 = f1.get_Curve(1);
			XYZ xyz = f1.get_Point(0);
			XYZ xyz2 = f1.get_Point(1);
			Curve c3 = f2.get_Curve(0);
			Curve c4 = f2.get_Curve(1);
			XYZ xyz3 = f2.get_Point(0);
			XYZ xyz4 = f2.get_Point(1);
			return xyz.IsAlmostEqualTo(xyz3) && xyz2.IsAlmostEqualTo(xyz4) && HcGeomUtil.CurvesCoincident(c, c3) && HcGeomUtil.CurvesCoincident(c2, c4);
		}

		public static bool CurvesCoincident(Curve c1, Curve c2)
		{
			if (null == c1 || null == c2)
			{
				return false;
			}
			if (c1 == null && c2 == null)
			{
				return true;
			}
			if (c1 == null || c2 == null)
			{
				return false;
			}
			if (c1.GetType() != c2.GetType())
			{
				return false;
			}
			List<XYZ> list = c1.Tessellate() as List<XYZ>;
			List<XYZ> list2 = c2.Tessellate() as List<XYZ>;
			if (list.Count != list2.Count)
			{
				return false;
			}
			bool flag = true;
			bool flag2 = true;
			int count = list.Count;
			for (int i = 0; i < count; i++)
			{
				if (!list[i].IsAlmostEqualTo(list2[i]))
				{
					flag = false;
					break;
				}
			}
			if (!flag)
			{
				for (int j = 0; j < count; j++)
				{
					if (!list[j].IsAlmostEqualTo(list2[count - j - 1]))
					{
						flag2 = false;
						break;
					}
				}
			}
			return flag || flag2;
		}

		public static bool HermiteFacesCoincident(HermiteFace f1, HermiteFace f2)
		{
			if (null == f1 || null == f2)
			{
				return false;
			}
			if (f1.Points.Count != f2.Points.Count || f2.MixedDerivs.Count != f2.MixedDerivs.Count)
			{
				return false;
			}
			int count = f1.Points.Count;
			for (int i = 0; i < count; i++)
			{
				if (!f1.Points[i].IsAlmostEqualTo(f2.Points[i]))
				{
					return false;
				}
			}
			int count2 = f1.MixedDerivs.Count;
			for (int j = 0; j < count2; j++)
			{
				if (!f1.MixedDerivs[j].IsAlmostEqualTo(f2.MixedDerivs[j]))
				{
					return false;
				}
			}
			return true;
		}

		public static bool RevolvedFacesCoincident(RevolvedFace f1, RevolvedFace f2)
		{
			return !(null == f1) && !(null == f2) && f1.Axis.IsAlmostEqualTo(f2.Axis) && f1.Origin.IsAlmostEqualTo(f2.Origin) && HcGeomUtil.CurvesCoincident(f1.Curve, f2.Curve);
		}

		public static bool CylindricalFacesCoincident(CylindricalFace f1, CylindricalFace f2)
		{
			return !(null == f1) && !(null == f2) && (f1.Axis.IsAlmostEqualTo(f2.Axis) && f1.Origin.IsAlmostEqualTo(f2.Origin) && f1.get_Radius(0).IsAlmostEqualTo(f2.get_Radius(0)) && f1.get_Radius(1).IsAlmostEqualTo(f2.get_Radius(1)));
		}

		public static bool ConicalFacesCoincident(ConicalFace f1, ConicalFace f2)
		{
			return !(null == f1) && !(null == f2) && (f1.Axis.IsAlmostEqualTo(f2.Axis) && f1.Origin.IsAlmostEqualTo(f2.Origin) && f1.get_Radius(0).IsAlmostEqualTo(f2.get_Radius(0)) && f1.get_Radius(1).IsAlmostEqualTo(f2.get_Radius(1)) && Math.Abs(f1.HalfAngle - f2.HalfAngle) < 1.0);
		}

		public static bool PlanarFacesCoincident(PlanarFace f1, PlanarFace f2)
		{
			if (null == f1 || null == f2)
			{
				return false;
			}
			XYZ xyz = f1.FaceNormal();
			XYZ xyz2 = f2.FaceNormal();
			if (f1.Origin.IsAlmostEqualTo(f2.Origin) && xyz.IsAlmostEqualTo(xyz2))
			{
				return true;
			}
			if (xyz.IsAlmostEqualTo(xyz2) || xyz.IsAlmostEqualTo(-xyz2))
			{
				foreach (object obj in f2.EdgeLoops)
				{
					foreach (object obj2 in ((EdgeArray)obj))
					{
						XYZ xyz3 = ((Edge)obj2).Evaluate(0.0);
						IntersectionResult intersectionResult = f1.Project(xyz3);
						if (intersectionResult != null)
						{
							if (Math.Abs(intersectionResult.Distance) < 1.0)
							{
								return true;
							}
							return false;
						}
					}
				}
				return false;
			}
			return false;
		}

		private const double DOUBLE_EPS = 1.0;
	}
}
